home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gxcmap.c < prev    next >
C/C++ Source or Header  |  1997-05-06  |  27KB  |  777 lines

  1. /* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gxcmap.c */
  20. /* Color mapping for Ghostscript */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gsccolor.h"
  24. #include "gxcspace.h"
  25. #include "gxfarith.h"
  26. #include "gxfrac.h"
  27. #include "gxdcconv.h"
  28. #include "gxdevice.h"
  29. #include "gxcmap.h"
  30. #include "gxlum.h"
  31. #include "gzstate.h"
  32. #include "gxdither.h"
  33.  
  34. /* Structure descriptor */
  35. public_st_device_color();
  36. #define cptr ((gx_device_color *)vptr)
  37. private ENUM_PTRS_BEGIN(device_color_enum_ptrs) {
  38.     struct_proc_enum_ptrs((*proc)) = cptr->type->enum_ptrs;
  39.     if ( proc == 0 )
  40.       return 0;
  41.     return (*proc)(vptr, size, index, pep);
  42. } ENUM_PTRS_END
  43. private RELOC_PTRS_BEGIN(device_color_reloc_ptrs) {
  44.     struct_proc_reloc_ptrs((*proc)) = cptr->type->reloc_ptrs;
  45.     if ( proc != 0 )
  46.       (*proc)(vptr, size, gcst);
  47. } RELOC_PTRS_END
  48. #undef cptr
  49.  
  50. /* ------ Trace device mapping procedures ------ */
  51.  
  52. /* If DEBUG is defined, these procedures substitute for direct calls */
  53. /* on the device map_{rgb,cmyk}_color procedures. */
  54.  
  55. gx_color_index
  56. gx_proc_map_rgb_color(gx_device *dev,
  57.   gx_color_value vr, gx_color_value vg, gx_color_value vb)
  58. {    gx_color_index cindex =
  59.       (*dev_proc(dev, map_rgb_color))(dev, vr, vg, vb);
  60.     if_debug5('C', "%s [C]RGB %u,%u,%u -> color 0x%lx\n",
  61.           dev->dname, (uint)vr, (uint)vg, (uint)vb, (ulong)cindex);
  62.     return cindex;
  63. }
  64.  
  65. gx_color_index
  66. gx_proc_map_rgb_alpha_color(gx_device *dev,
  67.   gx_color_value vr, gx_color_value vg, gx_color_value vb, gx_color_value va)
  68. {    gx_color_index cindex =
  69.       (*dev_proc(dev, map_rgb_alpha_color))(dev, vr, vg, vb, va);
  70.     if_debug6('C', "[C]%s RGBA %u,%u,%u,%u -> color 0x%lx\n",
  71.           dev->dname, (uint)vr, (uint)vg, (uint)vb, (uint)va,
  72.           (ulong)cindex);
  73.     return cindex;
  74. }
  75.  
  76. gx_color_index
  77. gx_proc_map_cmyk_color(gx_device *dev,
  78.   gx_color_value vc, gx_color_value vm, gx_color_value vy, gx_color_value vk)
  79. {    gx_color_index cindex =
  80.       (*dev_proc(dev, map_cmyk_color))(dev, vc, vm, vy, vk);
  81.     if_debug6('C', "[C]%s CMYK %u,%u,%u,%u -> color 0x%lx\n",
  82.           dev->dname, (uint)vc, (uint)vm, (uint)vy, (uint)vk,
  83.           (ulong)cindex);
  84.     return cindex;
  85. }
  86.  
  87. /* ---------------- Device color rendering ---------------- */
  88.  
  89. private cmap_proc_gray(cmap_gray_halftoned);
  90. private cmap_proc_gray(cmap_gray_direct);
  91. private cmap_proc_gray(cmap_gray_to_rgb_halftoned);
  92. private cmap_proc_gray(cmap_gray_to_rgb_direct);
  93. private cmap_proc_gray(cmap_gray_to_cmyk_halftoned);
  94. private cmap_proc_gray(cmap_gray_to_cmyk_direct);
  95. private cmap_proc_rgb(cmap_rgb_halftoned);
  96. private cmap_proc_rgb(cmap_rgb_direct);
  97. private cmap_proc_rgb(cmap_rgb_to_gray_halftoned);
  98. private cmap_proc_rgb(cmap_rgb_to_gray_direct);
  99. private cmap_proc_rgb(cmap_rgb_to_cmyk);
  100. #define cmap_cmyk_halftoned cmap_cmyk_direct
  101. private cmap_proc_cmyk(cmap_cmyk_direct);
  102. private cmap_proc_cmyk(cmap_cmyk_to_gray);
  103. private cmap_proc_cmyk(cmap_cmyk_to_rgb);
  104. #ifdef DPNEXT
  105. private cmap_proc_rgb_alpha(cmap_rgb_alpha_halftoned);
  106. private cmap_proc_rgb_alpha(cmap_rgb_alpha_direct);
  107. /* Procedure names are only guaranteed unique to 23 characters.... */
  108. private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_halftoned);
  109. private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_direct);
  110. private cmap_proc_rgb_alpha(cmap_rgb_alpha_to_cmyk);
  111. #endif
  112.  
  113. private const gx_color_map_procs
  114.   cmap_gray_few =
  115.    { cmap_gray_halftoned, cmap_rgb_to_gray_halftoned, cmap_cmyk_to_gray
  116. #ifdef DPNEXT
  117.      , cmap_rgb_alpha2gray_halftoned
  118. #endif
  119.    },
  120.   cmap_gray_many =
  121.    { cmap_gray_direct, cmap_rgb_to_gray_direct, cmap_cmyk_to_gray
  122. #ifdef DPNEXT
  123.      , cmap_rgb_alpha2gray_direct
  124. #endif
  125.    },
  126.   cmap_rgb_few =
  127.    { cmap_gray_to_rgb_halftoned, cmap_rgb_halftoned, cmap_cmyk_to_rgb
  128. #ifdef DPNEXT
  129.      , cmap_rgb_alpha_halftoned
  130. #endif
  131.    },
  132.   cmap_rgb_many =
  133.    { cmap_gray_to_rgb_direct, cmap_rgb_direct, cmap_cmyk_to_rgb
  134. #ifdef DPNEXT
  135.      , cmap_rgb_alpha_direct
  136. #endif
  137.    },
  138.   cmap_cmyk_few =
  139.    { cmap_gray_to_cmyk_halftoned, cmap_rgb_to_cmyk, cmap_cmyk_halftoned
  140. #ifdef DPNEXT
  141.      , cmap_rgb_alpha_to_cmyk
  142. #endif
  143.    },
  144.   cmap_cmyk_many =
  145.    { cmap_gray_to_cmyk_direct, cmap_rgb_to_cmyk, cmap_cmyk_direct
  146. #ifdef DPNEXT
  147.      , cmap_rgb_alpha_to_cmyk
  148. #endif
  149.    };
  150.  
  151. const gx_color_map_procs *cmap_procs_default = &cmap_gray_many;
  152.  
  153. private const gx_color_map_procs _ds *cmap_few[] = {
  154.     0, &cmap_gray_few, 0, &cmap_rgb_few, &cmap_cmyk_few
  155. };
  156.  
  157. private const gx_color_map_procs _ds *cmap_many[] = {
  158.     0, &cmap_gray_many, 0, &cmap_rgb_many, &cmap_cmyk_many
  159. };
  160.  
  161. /* Determine the color mapping procedures for a device. */
  162. const gx_color_map_procs *
  163. gx_device_cmap_procs(const gx_device *dev)
  164. {    return ((gx_device_has_color(dev) ? dev->color_info.max_color :
  165.          dev->color_info.max_gray) >= 31 ? cmap_many : cmap_few)
  166.         [dev->color_info.num_components];
  167. }
  168.  
  169. /* Set the color mapping procedures in the graphics state. */
  170. void
  171. gx_set_cmap_procs(gs_imager_state *pis, const gx_device *dev)
  172. {    pis->cmap_procs = gx_device_cmap_procs(dev);
  173. }
  174.  
  175. /* Remap the color in the graphics state. */
  176. int
  177. gx_remap_color(gs_state *pgs)
  178. {    const gs_color_space *pcs = pgs->color_space;
  179.     /* The current color in the graphics state is always used for */
  180.     /* the texture, never for the source. */
  181.     return (*pcs->type->remap_color)(pgs->ccolor, pcs, pgs->dev_color,
  182.                      (gs_imager_state *)pgs, pgs->device,
  183.                      gs_color_select_texture);
  184. }
  185.  
  186. /* Indicate that a color space has no underlying concrete space. */
  187. const gs_color_space *
  188. gx_no_concrete_space(const gs_color_space *pcs, const gs_imager_state *pis)
  189. {    return NULL;
  190. }
  191.  
  192. /* Indicate that a color space is concrete. */
  193. const gs_color_space *
  194. gx_same_concrete_space(const gs_color_space *pcs, const gs_imager_state *pis)
  195. {    return pcs;
  196. }
  197.  
  198. /* Indicate that a color cannot be concretized. */
  199. int
  200. gx_no_concretize_color(const gs_client_color *pcc, const gs_color_space *pcs,
  201.   frac *pconc, const gs_imager_state *pis)
  202. {    return_error(gs_error_rangecheck);
  203. }
  204.  
  205. /* By default, remap a color by concretizing it and then */
  206. /* remapping the concrete color. */
  207. int
  208. gx_default_remap_color(const gs_client_color *pcc, const gs_color_space *pcs,
  209.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  210.   gs_color_select_t select)
  211. {    frac conc[4];
  212.     const gs_color_space *pconcs;
  213.     int code = (*pcs->type->concretize_color)(pcc, pcs, conc, pis);
  214.  
  215.     if ( code < 0 )
  216.       return code;
  217.     pconcs = cs_concrete_space(pcs, pis);
  218.     return (*pconcs->type->remap_concrete_color)(conc, pdc, pis, dev,
  219.                              select);
  220. }
  221.  
  222. /* Color remappers for the standard color spaces. */
  223. /* Note that we use D... instead of Device... in some places because */
  224. /* gcc under VMS only retains 23 characters of procedure names. */
  225.  
  226. #define unit_frac(v, ftemp)\
  227.   (ftemp = (v),\
  228.    (is_fneg(ftemp) ? frac_0 : is_fge1(ftemp) ? frac_1 : float2frac(ftemp)))
  229.  
  230. /* DeviceGray */
  231. int
  232. gx_concretize_DeviceGray(const gs_client_color *pc, const gs_color_space *pcs,
  233.   frac *pconc, const gs_imager_state *pis)
  234. {    float ftemp;
  235.     pconc[0] = unit_frac(pc->paint.values[0], ftemp);
  236.     return 0;
  237. }
  238. int
  239. gx_remap_concrete_DGray(const frac *pconc,
  240.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  241.   gs_color_select_t select)
  242. {    (*pis->cmap_procs->map_gray)
  243.       (pconc[0], pdc, pis, dev, select);
  244.     return 0;
  245. }
  246. int
  247. gx_remap_DeviceGray(const gs_client_color *pc, const gs_color_space *pcs,
  248.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  249.   gs_color_select_t select)
  250. {    float ftemp;
  251.     (*pis->cmap_procs->map_gray)
  252.       (unit_frac(pc->paint.values[0], ftemp),
  253.        pdc, pis, dev, select);
  254.     return 0;
  255. }
  256.  
  257. /* DeviceRGB */
  258. int
  259. gx_concretize_DeviceRGB(const gs_client_color *pc, const gs_color_space *pcs,
  260.   frac *pconc, const gs_imager_state *pis)
  261. {    float ftemp;
  262.     pconc[0] = unit_frac(pc->paint.values[0], ftemp);
  263.     pconc[1] = unit_frac(pc->paint.values[1], ftemp);
  264.     pconc[2] = unit_frac(pc->paint.values[2], ftemp);
  265.     return 0;
  266. }
  267. int
  268. gx_remap_concrete_DRGB(const frac *pconc,
  269.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  270.   gs_color_select_t select)
  271. {    gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2], pdc, pis, dev,
  272.                   select);
  273.     return 0;
  274. }
  275. int
  276. gx_remap_DeviceRGB(const gs_client_color *pc, const gs_color_space *pcs,
  277.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  278.   gs_color_select_t select)
  279. {    float ft0, ft1, ft2;
  280.     gx_remap_concrete_rgb(unit_frac(pc->paint.values[0], ft0),
  281.                   unit_frac(pc->paint.values[1], ft1),
  282.                   unit_frac(pc->paint.values[2], ft2),
  283.                   pdc, pis, dev, select);
  284.     return 0;
  285. }
  286.  
  287. /* DeviceCMYK */
  288. int
  289. gx_concretize_DeviceCMYK(const gs_client_color *pc, const gs_color_space *pcs,
  290.   frac *pconc, const gs_imager_state *pis)
  291. {    float ftemp;
  292.     pconc[0] = unit_frac(pc->paint.values[0], ftemp);
  293.     pconc[1] = unit_frac(pc->paint.values[1], ftemp);
  294.     pconc[2] = unit_frac(pc->paint.values[2], ftemp);
  295.     pconc[3] = unit_frac(pc->paint.values[3], ftemp);
  296.     return 0;
  297. }
  298. int
  299. gx_remap_concrete_DCMYK(const frac *pconc,
  300.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  301.   gs_color_select_t select)
  302. {    gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3], pdc,
  303.                    pis, dev, select);
  304.     return 0;
  305. }
  306. int
  307. gx_remap_DeviceCMYK(const gs_client_color *pc, const gs_color_space *pcs,
  308.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  309.   gs_color_select_t select)
  310. {    float ft0, ft1, ft2, ft3;
  311.     gx_remap_concrete_cmyk(unit_frac(pc->paint.values[0], ft0),
  312.                    unit_frac(pc->paint.values[1], ft1),
  313.                    unit_frac(pc->paint.values[2], ft2),
  314.                    unit_frac(pc->paint.values[3], ft3),
  315.                    pdc, pis, dev, select);
  316.     return 0;
  317. }
  318.  
  319. /* ------ Render Gray color. ------ */
  320.  
  321. private void
  322. cmap_gray_halftoned(frac gray, gx_device_color *pdc,
  323.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  324. {    if ( gx_render_gray(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), pdc, pis, dev, select) == 1 )
  325.       gx_color_load_select(pdc, pis, dev, select);
  326. }
  327.  
  328. private void
  329. cmap_gray_direct(frac gray, gx_device_color *pdc, const gs_imager_state *pis,
  330.   gx_device *dev, gs_color_select_t select)
  331. {    frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
  332.     gx_color_value cv_gray = frac2cv(mgray);
  333.     gx_color_index color =
  334.       (pis->alpha == gx_max_color_value ?
  335.        gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
  336.        gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, pis->alpha));
  337.     if ( color == gx_no_color_index )
  338.     {    if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
  339.           gx_color_load_select(pdc, pis, dev, select);
  340.         return;
  341.     }
  342.     color_set_pure(pdc, color);
  343. }
  344.  
  345. private void
  346. cmap_gray_to_rgb_halftoned(frac gray, gx_device_color *pdc,
  347.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  348. {    cmap_rgb_halftoned(gray, gray, gray, pdc, pis, dev, select);
  349. }
  350.  
  351. private void
  352. cmap_gray_to_rgb_direct(frac gray, gx_device_color *pdc,
  353.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  354. {    cmap_rgb_direct(gray, gray, gray, pdc, pis, dev, select);
  355. }
  356.  
  357. private void
  358. cmap_gray_to_cmyk_halftoned(frac gray, gx_device_color *pdc,
  359.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  360. {    /*
  361.      * Per the last paragraph of section 6.3 (p. 309) of the
  362.      * PostScript Language Reference Manual, 2nd Edition,
  363.      * we must bypass the C, M, and Y transfer functions in this case.
  364.      */
  365.     frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
  366.     if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
  367.       gx_color_load_select(pdc, pis, dev, select);
  368. }
  369.  
  370. private void
  371. cmap_gray_to_cmyk_direct(frac gray, gx_device_color *pdc,
  372.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  373. {    /*
  374.      * Per the last paragraph of section 6.3 (p. 309) of the
  375.      * PostScript Language Reference Manual, 2nd Edition,
  376.      * we must bypass the C, M, and Y transfer functions in this case.
  377.      */
  378.     frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
  379.     frac mblack = frac_1 - mgray;
  380.     gx_color_index color =
  381.       gx_map_cmyk_color(dev,
  382.                 frac2cv(frac_0), frac2cv(frac_0),
  383.                 frac2cv(frac_0), frac2cv(mblack));
  384.     if ( color != gx_no_color_index )
  385.     {    color_set_pure(pdc, color);
  386.         return;
  387.     }
  388.     if ( gx_render_gray(mgray, pdc, pis, dev, select) == 1 )
  389.       gx_color_load_select(pdc, pis, dev, select);
  390. }
  391.  
  392. /* ------ Render RGB color. ------ */
  393.  
  394. /*
  395.  * This code should test r == g and g == b and then use the gray
  396.  * rendering procedures.  The Adobe documentation allows this:
  397.  * conversion between color spaces occurs before the transfer function
  398.  * and halftoning.  However, output from FrameMaker (mis)uses the
  399.  * transfer function to provide the equivalent of indexed color;
  400.  * it requires the color components to be passed through unchanged.
  401.  * For this reason, we have to make the check after the transfer
  402.  * function rather than before.
  403.  *
  404.  * Since this procedure is used so heavily, we duplicate most of its code
  405.  * rather than making a text for color_info.max_color >= 31.
  406.  */
  407.  
  408. private void
  409. cmap_rgb_halftoned(frac r, frac g, frac b, gx_device_color *pdc,
  410.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  411. {    frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
  412.     frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
  413.     frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
  414.     if ( (mred == mgreen && mred == mblue ?    /* gray shade */
  415.           gx_render_gray(mred, pdc, pis, dev, select) :
  416.           gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1 )
  417.       gx_color_load_select(pdc, pis, dev, select);
  418. }
  419.  
  420. private void
  421. cmap_rgb_direct(frac r, frac g, frac b, gx_device_color *pdc,
  422.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  423. {    frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
  424.     frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
  425.     frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
  426.     gx_color_index color =
  427.       (pis->alpha == gx_max_color_value ?
  428.        gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
  429.                 frac2cv(mblue)) :
  430.        gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
  431.                   frac2cv(mblue), pis->alpha));
  432.     if ( color != gx_no_color_index )
  433.       {    color_set_pure(pdc, color);
  434.         return;
  435.       }
  436.     if ( (mred == mgreen && mred == mblue ?    /* gray shade */
  437.           gx_render_gray(mred, pdc, pis, dev, select) :
  438.           gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1 )
  439.       gx_color_load_select(pdc, pis, dev, select);
  440. }
  441.  
  442. private void
  443. cmap_rgb_to_gray_halftoned(frac r, frac g, frac b, gx_device_color *pdc,
  444.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  445. {    cmap_gray_halftoned(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
  446. }
  447.  
  448. private void
  449. cmap_rgb_to_gray_direct(frac r, frac g, frac b, gx_device_color *pdc,
  450.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  451. {    cmap_gray_direct(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
  452. }
  453.  
  454. private void
  455. cmap_rgb_to_cmyk(frac r, frac g, frac b, gx_device_color *pdc,
  456.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  457. {    frac cmyk[4];
  458.     color_rgb_to_cmyk(r, g, b, pis, cmyk);
  459.     (*pis->cmap_procs->map_cmyk)(cmyk[0], cmyk[1], cmyk[2], cmyk[3], pdc, pis, dev, select);
  460. }
  461.  
  462. /* ------ Render CMYK color. ------ */
  463.  
  464. private void
  465. cmap_cmyk_to_gray(frac c, frac m, frac y, frac k, gx_device_color *pdc,
  466.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  467. {    (*pis->cmap_procs->map_gray)(color_cmyk_to_gray(c, m, y, k, pis), pdc, pis, dev, select);
  468. }
  469.  
  470. private void
  471. cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color *pdc,
  472.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  473. {    frac mcyan = frac_1 - gx_map_color_frac(pis, frac_1 - c, effective_transfer.colored.red);
  474.     frac mmagenta = frac_1 - gx_map_color_frac(pis, frac_1 - m, effective_transfer.colored.green);
  475.     frac myellow = frac_1 - gx_map_color_frac(pis, frac_1 - y, effective_transfer.colored.blue);
  476.     frac mblack = frac_1 - gx_map_color_frac(pis, frac_1 - k, effective_transfer.colored.gray);
  477.     /* We make a test for direct vs. halftoned, rather than */
  478.     /* duplicating most of the code of this procedure. */
  479.     if ( dev->color_info.max_color >= 31 )
  480.     {    gx_color_index color =
  481.             gx_map_cmyk_color(dev,
  482.                       frac2cv(mcyan), frac2cv(mmagenta),
  483.                       frac2cv(myellow), frac2cv(mblack));
  484.         if ( color != gx_no_color_index )
  485.         {    color_set_pure(pdc, color);
  486.             return;
  487.         }
  488.     }
  489.     /* Don't convert colors with C = M = Y to gray shades: */
  490.     /* on a CMYK device, this may produce quite different output. */
  491.     if ( gx_render_cmyk(mcyan, mmagenta, myellow, mblack, pdc, pis, dev, select) == 1 )
  492.       gx_color_load_select(pdc, pis, dev, select);
  493. }
  494.  
  495. private void
  496. cmap_cmyk_to_rgb(frac c, frac m, frac y, frac k, gx_device_color *pdc,
  497.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  498. {    frac rgb[3];
  499.     color_cmyk_to_rgb(c, m, y, k, pis, rgb);
  500.     (*pis->cmap_procs->map_rgb)(rgb[0], rgb[1], rgb[2], pdc, pis, dev, select);
  501. }
  502.  
  503. #ifdef DPNEXT
  504.  
  505. /* ------ Render RGB+alpha color. ------ */
  506.  
  507. private void
  508. cmap_rgb_alpha2gray_halftoned(frac r, frac g, frac b, frac alpha,
  509.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  510.   gs_color_select_t select)
  511. {    frac gray = color_rgb_to_gray(r, g, b, pis);
  512.  
  513.     if ( gx_render_gray_alpha(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), frac2cv(alpha), pdc, pis, dev, select) == 1 )
  514.       gx_color_load_select(pdc, pis, dev, select);
  515. }
  516.  
  517. private void
  518. cmap_rgb_alpha2gray_direct(frac r, frac g, frac b, frac alpha,
  519.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  520.   gs_color_select_t select)
  521. {    frac gray = color_rgb_to_gray(r, g, b, pis);
  522.     frac mgray =
  523.       gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
  524.     gx_color_value cv_gray = frac2cv(mgray);
  525.     gx_color_value cv_alpha = frac2cv(alpha);
  526.     gx_color_index color =
  527.       (cv_alpha == gx_max_color_value ?
  528.        gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
  529.        gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, cv_alpha));
  530.  
  531.     if ( color == gx_no_color_index )
  532.       { if ( gx_render_gray_alpha(mgray, cv_alpha, pdc, pis, dev, select) == 1 )
  533.           gx_color_load_select(pdc, pis, dev, select);
  534.         return;
  535.       }
  536.     color_set_pure(pdc, color);
  537. }
  538.  
  539. private void
  540. cmap_rgb_alpha_halftoned(frac r, frac g, frac b, frac alpha,
  541.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  542.   gs_color_select_t select)
  543. {    frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
  544.     frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
  545.     frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
  546.     gx_color_value cv_alpha = frac2cv(alpha);
  547.  
  548.     if ( (mred == mgreen && mred == mblue ?    /* gray shade */
  549.           gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
  550.           gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1 )
  551.       gx_color_load_select(pdc, pis, dev, select);
  552. }
  553.  
  554. private void
  555. cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color *pdc,
  556.   const gs_imager_state *pis, gx_device *dev, gs_color_select_t select)
  557. {    frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
  558.     frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
  559.     frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
  560.     gx_color_value cv_alpha = frac2cv(alpha);
  561.     gx_color_index color =
  562.       (cv_alpha == gx_max_color_value ?
  563.        gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
  564.                 frac2cv(mblue)) :
  565.        gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
  566.                   frac2cv(mblue), cv_alpha));
  567.  
  568.     if ( color != gx_no_color_index )
  569.       {    color_set_pure(pdc, color);
  570.         return;
  571.       }
  572.     if ( (mred == mgreen && mred == mblue ?    /* gray shade */
  573.           gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
  574.           gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1 )
  575.       gx_color_load_select(pdc, pis, dev, select);
  576. }
  577.  
  578. /* Currently CMYK devices can't handle alpha. */
  579. /* Just multiply the values towards white. */
  580. private void
  581. cmap_rgb_alpha_to_cmyk(frac r, frac g, frac b, frac alpha,
  582.   gx_device_color *pdc, const gs_imager_state *pis, gx_device *dev,
  583.   gs_color_select_t select)
  584. {    frac white = frac_1 - alpha;
  585.  
  586.     cmap_rgb_to_cmyk((frac)((long)r * alpha / frac_1) + white,
  587.              (frac)((long)g * alpha / frac_1) + white,
  588.              (frac)((long)b * alpha / frac_1) + white,
  589.              pdc, pis, dev, select);
  590. }
  591.  
  592. #endif
  593.  
  594. /* ------ Transfer function mapping ------ */
  595.  
  596. /* Define the generic transfer function for the library layer. */
  597. /* This just returns what's already in the map. */
  598. float
  599. gs_mapped_transfer(floatp value, const gx_transfer_map *pmap)
  600. {    return gx_map_color_float(pmap, value);
  601. }
  602.  
  603. #if FRAC_MAP_INTERPOLATE        /* NOTA BENE */
  604.  
  605. /* Map a color fraction through a transfer map. */
  606. /* We only use this if we are interpolating. */
  607. frac
  608. gx_color_frac_map(frac cv, const frac *values)
  609. {
  610. #define cp_frac_bits (frac_bits - log2_transfer_map_size)
  611.     int cmi = frac2bits_floor(cv, log2_transfer_map_size);
  612.     frac mv = values[cmi];
  613.     int rem, mdv;
  614.     /* Interpolate between two adjacent values if needed. */
  615.     rem = cv - bits2frac(cmi, log2_transfer_map_size);
  616.     if ( rem == 0 ) return mv;
  617.     mdv = values[cmi + 1] - mv;
  618. #if arch_ints_are_short
  619.     /* Only use long multiplication if necessary. */
  620.     if ( mdv < -1 << (16 - cp_frac_bits) ||
  621.          mdv > 1 << (16 - cp_frac_bits)
  622.        )
  623.         return mv + (uint)(((ulong)rem * mdv) >> cp_frac_bits);
  624. #endif
  625.     return mv + ((rem * mdv) >> cp_frac_bits);
  626. #undef cp_frac_bits
  627. }
  628.  
  629. #endif                    /* FRAC_MAP_INTERPOLATE */
  630.  
  631. /* ------ Default device color mapping ------ */
  632.  
  633. /* RGB mapping for black-and-white devices */
  634.  
  635. /* White-on-black */
  636. gx_color_index
  637. gx_default_w_b_map_rgb_color(gx_device *dev,
  638.   gx_color_value r, gx_color_value g, gx_color_value b)
  639. {    /* Map values >= 1/2 to 1, < 1/2 to 0. */
  640.     return ((r | g | b) > gx_max_color_value / 2 ?
  641.         (gx_color_index)1 : (gx_color_index)0);
  642. }
  643. int
  644. gx_default_w_b_map_color_rgb(gx_device *dev, gx_color_index color,
  645.   gx_color_value prgb[3])
  646. {    /* Map 1 to max_value, 0 to 0. */
  647.     prgb[0] = prgb[1] = prgb[2] = -(gx_color_value)color;
  648.     return 0;
  649. }
  650. /* Black-on-white */
  651. gx_color_index
  652. gx_default_b_w_map_rgb_color(gx_device *dev,
  653.   gx_color_value r, gx_color_value g, gx_color_value b)
  654. {    /* Map values >= 1/2 to 0, < 1/2 to 1. */
  655.     return ((r | g | b) > gx_max_color_value / 2 ?
  656.         (gx_color_index)0 : (gx_color_index)1);
  657. }
  658. int
  659. gx_default_b_w_map_color_rgb(gx_device *dev, gx_color_index color,
  660.   gx_color_value prgb[3])
  661. {    /* Map 0 to max_value, 1 to 0. */
  662.     prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
  663.     return 0;
  664. }
  665.  
  666. /* RGB mapping for gray-scale devices */
  667.  
  668. gx_color_index
  669. gx_default_gray_map_rgb_color(gx_device *dev,
  670.   gx_color_value r, gx_color_value g, gx_color_value b)
  671. {    /* We round the value rather than truncating it. */
  672.     gx_color_value gray =
  673.       (((r * (ulong)lum_red_weight) +
  674.         (g * (ulong)lum_green_weight) +
  675.         (b * (ulong)lum_blue_weight) +
  676.         (lum_all_weights / 2)) / lum_all_weights
  677.        * dev->color_info.max_gray +
  678.        (gx_max_color_value / 2)) / gx_max_color_value;
  679.     return gray;
  680. }
  681.  
  682. int
  683. gx_default_gray_map_color_rgb(gx_device *dev, gx_color_index color,
  684.   gx_color_value prgb[3])
  685. {    gx_color_value gray =
  686.         color * gx_max_color_value / dev->color_info.max_gray;
  687.     prgb[0] = gray;
  688.     prgb[1] = gray;
  689.     prgb[2] = gray;
  690.     return 0;
  691. }
  692.  
  693. /* RGB mapping for 24-bit true (RGB) color devices */
  694.  
  695. gx_color_index
  696. gx_default_rgb_map_rgb_color(gx_device *dev,
  697.   gx_color_value r, gx_color_value g, gx_color_value b)
  698. {    if ( dev->color_info.depth == 24 )
  699.         return gx_color_value_to_byte(b) +
  700.             ((uint)gx_color_value_to_byte(g) << 8) +
  701.             ((ulong)gx_color_value_to_byte(r) << 16);
  702.     else
  703.     {    uint bits_per_color = dev->color_info.depth / 3;
  704.         ulong max_value = (1 << bits_per_color) - 1;
  705.  
  706.         return ((r * max_value / gx_max_color_value) << (bits_per_color * 2)) +
  707.             ((g * max_value / gx_max_color_value) << (bits_per_color)) +
  708.             (b * max_value / gx_max_color_value);
  709.     }
  710. }
  711.  
  712. /* Map a color index to a r-g-b color. */
  713. int
  714. gx_default_rgb_map_color_rgb(gx_device *dev, gx_color_index color,
  715.   gx_color_value prgb[3])
  716. {    if ( dev->color_info.depth == 24 )
  717.     {    prgb[0] = gx_color_value_from_byte(color >> 16);
  718.         prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
  719.         prgb[2]    = gx_color_value_from_byte(color & 0xff);
  720.     }
  721.     else
  722.     {    uint bits_per_color = dev->color_info.depth / 3;
  723.         uint color_mask = (1 << bits_per_color) - 1;
  724.  
  725.         prgb[0] = ((color >> (bits_per_color * 2)) & color_mask) *
  726.             (ulong)gx_max_color_value / color_mask;
  727.         prgb[1] = ((color >> (bits_per_color)) & color_mask) *
  728.             (ulong)gx_max_color_value / color_mask;
  729.         prgb[2] = (color & color_mask) *
  730.             (ulong)gx_max_color_value / color_mask;
  731.     }
  732.     return 0;
  733. }
  734.  
  735. /* CMYK mapping for RGB devices (should never be called!) */
  736.  
  737. gx_color_index
  738. gx_default_map_cmyk_color(gx_device *dev,
  739.   gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
  740. {    /* Convert to RGB */
  741.     frac rgb[3];
  742.     color_cmyk_to_rgb(cv2frac(c), cv2frac(m), cv2frac(y), cv2frac(k),
  743.               NULL, rgb);
  744.     return gx_map_rgb_color(dev, frac2cv(rgb[0]),
  745.                 frac2cv(rgb[1]), frac2cv(rgb[2]));
  746. }
  747.  
  748. /* CMYK mapping for CMYK devices */
  749.  
  750. gx_color_index
  751. gx_default_cmyk_map_cmyk_color(gx_device *dev,
  752.   gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
  753. {    gx_color_index color =
  754.       (gx_color_value_to_byte(k) +
  755.        ((uint)gx_color_value_to_byte(y) << 8)) +
  756.       ((ulong)(gx_color_value_to_byte(m) +
  757.            ((uint)gx_color_value_to_byte(c) << 8)) << 16);
  758.  
  759.     return (color == gx_no_color_index ? color ^ 1 : color);
  760. }
  761.  
  762. /* Default mapping from RGB+alpha to RGB. */
  763.  
  764. gx_color_index
  765. gx_default_map_rgb_alpha_color(gx_device *dev,
  766.   gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
  767. {    /* Premultiply the values towards white. */
  768.     gx_color_value white = gx_max_color_value - alpha;
  769.  
  770.     if ( white == 0 )
  771.       return gx_map_rgb_color(dev, r, g, b);
  772.     return gx_map_rgb_color(dev,
  773.       (gx_color_value)((ulong)r * alpha / gx_max_color_value) + white,
  774.       (gx_color_value)((ulong)g * alpha / gx_max_color_value) + white,
  775.       (gx_color_value)((ulong)b * alpha / gx_max_color_value) + white);
  776. }
  777.